//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<IObject.cpp>
///	@path	~/src/object/
///	@date	2007/06/25
///	@desc	object interface.

#include "config/config.h"
#include "config/os.h"

#include "lib/utilities/time.h"
#include "lib/utilities/debug.h"

#include "object/IObject.h"

namespace xeres {

	// ctor
	IObject::IObject( void )
		// setup reference count
		: m_refCount( 0 )
		// setup flags
		, m_attrFlags( 0 )
	{
		// compile time IObject size check!
#ifdef	_DEBUG
		static const char IObject_Type_size_is_not_valid[ sizeof(IObject) == 16 ] = "";
#endif
	}

	// dtor
	IObject::~IObject( void )
	{
	}

	// is a ... class
	bool IObject::IsA( const WString& className ) const
	{
		TRACK_FUNCTION_SCOPE();

		// check self and ancient first
		if( className == GetClassName() || className == GetAncientName() )
			return true;

		// dispatch to class register

		return false;
	}

	// is a ... class
	bool IObject::IsA( const ClassID classId ) const
	{
		TRACK_FUNCTION_SCOPE();

		// check self and ancient first
		if( classId == GetClassID() || classId == GetAncientID() )
			return true;

		// dispatch to class register

		return ObjectFactory::IsCompatible( GetClassID() , classId );
	}
	// SetFlags
	void IObject::SetFlags( uint32 mask )
	{
		XS_ASSERT( ( mask & 0x0000000f ) == 0 );
		m_attrFlags |= mask;
	}
	// SetBaseFlags
	void IObject::SetBaseFlags( uint32 mask )
	{
		XS_ASSERT( ( mask & 0xfffffff0 ) == 0 );
		m_attrFlags |= mask;
	}

#pragma intrinsic(_InterlockedOr)

	// SetFlagsAsync
	uint32 IObject::SetFlagsAsync( uint32 mask )
	{
		return _InterlockedOr( (long*)&m_attrFlags , mask );
	}

	// ClearFlags
	void IObject::ClearFlags( uint32 mask )
	{
		XS_ASSERT( ( mask & 0x0000000f ) == 0 );
		m_attrFlags &= ~mask;
	}
	// ClearBaseFlags
	void IObject::ClearBaseFlags( uint32 mask )
	{
		XS_ASSERT( ( mask & 0xfffffff0 ) == 0 );
		m_attrFlags &= ~mask;
	}

#pragma intrinsic(_InterlockedAnd)

	// ClearFlagsAsync
	uint32 IObject::ClearFlagsAsync( uint32 mask )
	{
		return _InterlockedAnd( (long*)&m_attrFlags , ~mask );
	}

	void IObject::OnAddRef( int refCount )
	{
		TRACE_DEBUG( _S("%s : %x +ref %i->%i.") , GetClassName().c_str() , this ,
			refCount , refCount + 1 );
	}

	void IObject::OnReleaseRef( int refCount )
	{
		TRACE_DEBUG( _S("%s : %x -ref %i->%i.") , GetClassName().c_str() , this ,
			refCount , refCount - 1 );
	}

	// add reference
	void IObject::AddRef( void )
	{
		// check count
		assert( 0 <= m_refCount && m_refCount < INT_MAX );

#if XERES_IOBJECT_REFERENCE_DEBUG
		this->OnAddRef( m_refCount );
#endif

		// atomic add 1 on count
		atom_add( &m_refCount , 1 );
	}

	// release reference
	void IObject::ReleaseRef( void )
	{
		// check count
		assert( 0 < m_refCount && m_refCount < INT_MAX );

#if XERES_IOBJECT_REFERENCE_DEBUG
		this->OnReleaseRef( m_refCount );
#endif

		// atomic add -1 to decrease count
		if( atom_xchg_add( &m_refCount , -1 ) == 1 )
		{
			assert( m_refCount == 0 );
			// perform destruction
			delete this;
		}
	}

	// add reference without lock
	void IObject::AddRefUnsafe( void )
	{
		// check count
		assert( 0 <= m_refCount && m_refCount < INT_MAX );

#if XERES_IOBJECT_REFERENCE_DEBUG
		this->OnAddRef( m_refCount );
#endif

		// atomic add 1 on count
		++m_refCount;
	}

	// release reference without lock
	void IObject::ReleaseRefUnsafe( void )
	{
		// check count
		assert( 0 < m_refCount && m_refCount < INT_MAX );

#if XERES_IOBJECT_REFERENCE_DEBUG
		this->OnReleaseRef( m_refCount );
#endif

		// atomic add -1 to decrease count
		if( --m_refCount == 0 )
		{
			// perform destruction
			delete this;
		}
	}

	// GetRefCount
	int IObject::GetRefCount( void ) const
	{
		return m_refCount;
	}

	// return if object has only 1 ref
	bool IObject::IsUniqueRef( void ) const
	{
		return m_refCount == 1;
	}

	// static class name
	const WString& IObject::StaticClassName( void )
	{
		static const WString __IObjectClassName( _S("IObject") );
		return __IObjectClassName;
	}

	// static class ID
	const ClassID IObject::StaticClassID( void )
	{
		static ClassID __IObjectClassID = ObjectFactory::RegisterInterface(
			StaticClassName() , INVALID_CLASS_ID );
		return __IObjectClassID;
	}

	void * IObject::AllocateObject( size_t size , const ClassID id )
	{
		return ObjectFactory::AllocateObject( size , id );
	}
	
	void IObject::DeallocateObject( void * ptr , const ClassID id )
	{
		ObjectFactory::DeallocateObject( ptr , id );
	}

	void IObject::RegisterThisClass( const WString& name , const ClassID (*idFunction)( void ) )
	{
		do 
		{
			idFunction();
		} while(0);
	}
	
} // namespace xeres
